package com.withmiku.world.user.security;

import com.withmiku.world.user.entity.User;
import com.withmiku.world.user.service.UserService;
import com.withmiku.world.user.service.impl.CustomUserDetailsService;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class JwtFilter implements Filter {
    private final JwtUtils jwtUtils;
    private final UserService userService;
    private final CustomUserDetailsService customUserDetailsService;

    @Autowired
    public JwtFilter(JwtUtils jwtUtils,
                     @Qualifier("userServiceImpl") UserService userService,
                     CustomUserDetailsService customUserDetailsService) {
        this.jwtUtils = jwtUtils;
        this.userService = userService;
        this.customUserDetailsService = customUserDetailsService;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;

        String path = httpServletRequest.getRequestURI();

        // 白名单
        if (path.startsWith("/api/user/login")
                || path.startsWith("/api/user/register")
                || path.startsWith("/swagger-ui")
                || path.startsWith("/v3/api-docs")
                || path.startsWith("/uploads")) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        String header = httpServletRequest.getHeader("Authorization");

        if (header == null || !header.startsWith("Bearer ")) {
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpServletResponse.getWriter().write("Missing or invalid Authorization header");
            return;
        }

        String token = header.substring(7);
        if (!jwtUtils.validateToken(token)) {
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpServletResponse.getWriter().write("Invalid or expired token");
            return;
        }

        // 从token中提取用户名并放入请求属性
        String username = jwtUtils.extractUsername(token);
        if (username == null) {
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpServletResponse.getWriter().write("Invalid token payload");
            return;
        }

        User user = userService.findByUsername(username);
        if (user == null) {
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpServletResponse.getWriter().write("User not found");
            return;
        }

        // 对于已被封禁的用户，也能够正常注销
        if (path.startsWith("/api/user/logout")) {
            System.out.println("JwtFilter: logout放行成功");
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        // 检测用户状态
        if (user.getStatus() == 0) {
            httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            httpServletResponse.getWriter().write("Account has been banned, please contact admin");
            return;
        }

        UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);

        // 设置认证信息，让 Spring Security 知道当前用户是已认证状态
        UsernamePasswordAuthenticationToken auth =
                new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(auth);

        servletRequest.setAttribute("username", username);

        filterChain.doFilter(servletRequest, servletResponse);
    }
}
